from sys import version_info, argv
from PyQt4 import QtGui
from PyQt4 import QtCore
from PyQt4 import Qt
from threading import Thread
from time import sleep

import _cam as cam
import _movement as mov
import image_proc as im_proc
import params

#python2 compatibility fix
if version_info[0] == (2):
    from Queue import Queue, Empty, Full
else:
    from queue import Queue, Empty, Full

class MainApp(QtGui.QWidget): 
    def __init__(self):
        super(MainApp, self).__init__()     
        self.initUI()

    def initUI(self):
        self.setWindowTitle('Control')
        
        self.vgaCheckBox = QtGui.QCheckBox('Show VGA camera stream', self)
        self.depthCheckBox = QtGui.QCheckBox('Show depth sensor stream', self)
        self.traceCheckBox = QtGui.QCheckBox('Show trace stream', self)
        
        startButton = QtGui.QPushButton('Start', self) 
        stopButton = QtGui.QPushButton('Stop', self)
        thrLabel = QtGui.QLabel("Set maximum distance in <cm>", self)
        thrSlider = QtGui.QSlider(Qt.Qt.Horizontal, self)
        thrSlider.setMinimum(50)
        thrSlider.setMaximum(500)
        thrSlider.setSingleStep(1)
        thrSlider.setPageStep(10)
        thrSlider.setValue(params.MAX_DISTANCE)
        self.thrValue = QtGui.QLabel("Current value:" + str(thrSlider.value()), self)

        hbox = QtGui.QVBoxLayout()
        hbox.addStretch(1)
        hbox.addWidget(self.vgaCheckBox)
        hbox.addWidget(self.depthCheckBox)
        hbox.addWidget(self.traceCheckBox)
        hbox.addWidget(startButton)
        hbox.addWidget(stopButton)
        hbox.addWidget(thrLabel)
        hbox.addWidget(thrSlider)
        hbox.addWidget(self.thrValue)
        
        self.setLayout(hbox)
        
        self.move(100, 560)

        self.connect(self.vgaCheckBox, QtCore.SIGNAL('stateChanged(int)'), self.showVGA)
        self.connect(self.depthCheckBox, QtCore.SIGNAL('stateChanged(int)'), self.showDepth)
        self.connect(self.traceCheckBox, QtCore.SIGNAL('stateChanged(int)'), self.showTrace)
        self.connect(thrSlider, QtCore.SIGNAL("valueChanged(int)"), self.showSliderVal)
        self.connect(startButton, QtCore.SIGNAL('clicked()'), self.start)
        self.connect(stopButton, QtCore.SIGNAL('clicked()'), self.stop)
        
        cam.setTiltLevel("low")
        self.trigger = False

    def showSliderVal(self, value):
        self.thrValue.setText("Current value:" + str(value))
        params.MAX_DISTANCE = value
        
    def start(self):
        if self.trigger == False:
            self.trigger = True
            self.RGBQueue = Queue(maxsize = 5)
            self.depthQueue = Queue(maxsize = 5)
            self.gestureQueue = Queue(maxsize = 6)
            
            self.processThread = processImage(self.RGBQueue, self.depthQueue, self.gestureQueue, self)
            self.processThread.start()
                
            if self.depthCheckBox.checkState() == 2: 
                self.depthThread = displayImage(self, self.depthQueue, self.depthWin)
                self.depthThread.start()
            
            if self.vgaCheckBox.checkState() == 2:
                self.vgaThread = displayImage(self, self.RGBQueue, self.vgaWin)
                self.vgaThread.start()
            
            if self.traceCheckBox.checkState() == 2:
                self.traceThread = gestureAnalysis(self, self.gestureQueue, self.traceWin)
                self.traceThread.start()

    def showDepth(self,):
        if self.depthCheckBox.checkState() == 2:
            self.depthWin = ImageWindow("depth.jpg", "Depth Preview", (0, 20))
            self.depthWin.show()
        else:
            self.depthWin.close()
            
    def showVGA(self):
        if self.vgaCheckBox.checkState() == 2:
            self.vgaWin = ImageWindow("RGB.jpg", "RGB Preview", (640, 20))
            self.vgaWin.show()
        else:
            self.vgaWin.close()
            
    def showTrace(self):
        if self.traceCheckBox.checkState() == 2:
            self.traceWin = ImageWindow("trace.jpg", "Trace Preview", (400, 300))
            self.traceWin.show()
        else:
            self.traceWin.close()
    
    def stop(self):
        self.trigger = False
        sleep(0.2)
        
    def closeEvent(self, event):
        """Stop every thread using trigger"""
        if self.trigger == True:
            self.trigger = False
            sleep(0.2)
        try:
            self.vgaWin.close()
        except Exception:
            pass
        try:
            self.depthWin.close()
        except Exception:
            pass
        try:
            self.traceWin.close()
        except Exception:
            pass
        try:
            self.processThread.displayWindow.close()
        except Exception:
            pass

class processImage(Thread):
    """Class derived from Thread responsible initial processing of the images"""
    def __init__(self, RGBQueue, depthQueue, gestureQueue, app):
        self.RGBQueue = RGBQueue
        self.depthQueue = depthQueue
        self.gestureQueue = gestureQueue
        self.app = app
        self.ImProc = im_proc.ImageProcessor()
        self.displayWindow = StatusWindow("Status", (600, 530), 450, 240)
        self.displayWindow.show()
        Thread.__init__(self)
    def run(self):
        while self.app.trigger:
            self.ImProc.reinit()    #increment counters etc.
            if self.app.vgaCheckBox.checkState() == 2:                     
                try:
                    self.RGBQueue.put(self.ImProc.getRGBImage(), block = False)
                except Full:
                    print("RGB Queue is full!")
            
            self.ImProc.getDepthImage()
            self.ImProc.processImage()
            
            self.displayWindow.label.setText("LEFT HAND\n" + 
                                             "POSITION:\n" + str(self.ImProc.lParams.position) + "\n" 
                                             '{0} {1:.1f} '.format("AVG DIST:", self.ImProc.lParams.avgDistance) + "\n" + 
                                             '{0} {1:.1f} '.format("AREA:", self.ImProc.lParams.area) + "\n" + 
                                             "CENTER:" + str(self.ImProc.lParams.centerOfWeight) + "\n" + 
                                             "\nRIGHT HAND\n" + 
                                             "POSITION:\n" + str(self.ImProc.rParams.position) + "\n" 
                                             '{0} {1:.1f} '.format("AVG DIST:", self.ImProc.rParams.avgDistance) + "\n" + 
                                             '{0} {1:.1f} '.format("AREA:", self.ImProc.rParams.area) + "\n"
                                             "CENTER:" + str(self.ImProc.rParams.centerOfWeight)
                                             ) 
            
            if self.app.depthCheckBox.checkState() == 2:
                depthImageSelected = self.ImProc.getDepthImageWithSelection()
                try:
                    self.depthQueue.put(depthImageSelected, block = False)  
                except Full:
                    print("Depth Queue is full!")
                    
            if self.ImProc.handsTracked and self.app.traceCheckBox.checkState() == 2:
                try:
                    self.gestureQueue.put((self.ImProc.lParams, self.ImProc.rParams), block = False)
                except Full:
                    print("Gesture Queue is full!")
        
        self.displayWindow.close()

class ImageWindow(QtGui.QDialog):
    """Class inheriting after QDialog designed for displaying images"""
    def __init__(self, image, title, position):
        QtGui.QDialog.__init__(self)
        self.setWindowTitle(title)
                
        self.pixmap = QtGui.QPixmap(image)
        
        self.resize(self.pixmap.width(), self.pixmap.height())
        self.label = QtGui.QLabel(self)
        self.label.setAlignment(QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft)
        self.label.setPixmap(self.pixmap)
        self.move(position[0], position[1])
        
class StatusWindow(QtGui.QDialog):
    """Class inheriting after QDialog designed for displaying status"""
    def __init__(self, title, position, width, height):
        QtGui.QDialog.__init__(self)
        self.setWindowTitle(title)   
        self.resize(width, height)
        self.label = QtGui.QLabel(self)
        self.label.resize(width, height)
        self.label.setMargin(8)
        self.label.setAlignment(QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft)
#        self.label.setFont(QtGui.QFont("Segoe UI", 20))
        self.move(position[0], position[1])

class displayImage(Thread):
    """Class derived from Thread responsible for displaying preview images"""
    def __init__(self, app, queue, window):
        self.app = app
        self.queue = queue
        self.window = window
        Thread.__init__(self)
    def run(self):
        while self.app.trigger:
            try:
                self.img = self.queue.get(block = True, timeout = params.TIMEOUT)             
                self.window.pixmap = QtGui.QPixmap(self.img)
                self.window.label.setPixmap(self.window.pixmap) 
                self.queue.task_done()               
            except Empty:
                pass
            
class gestureAnalysis(Thread):
    """Class derived from Thread responsible for gesture analysis"""
    def __init__(self, app, queue, window):
        self.app = app
        self.queue = queue
        self.window = window    
        self.hands = mov.Hands()
        self.displayWindow = StatusWindow("Gesture in progress", (20, 650), 200, 80)
        self.displayWindow.show()
        Thread.__init__(self)
    def run(self):
        while self.app.trigger:
            try:
                [leftStatus, rightStatus] = self.queue.get(block = True, timeout = params.TIMEOUT)                     
                self.hands.update(leftStatus, rightStatus)  
                self.img = self.hands.getTraceImage()
                self.window.pixmap = QtGui.QPixmap(self.img)
                self.window.label.setPixmap(self.window.pixmap) 
                self.displayWindow.label.setText("LEFT HAND\n" + 
                                             "  IN PROGRESS:" + str(self.hands.leftHand.gestureInProgress) + 
                                             "  " + str(self.hands.leftHand.gestureCount) + "\n" + 
                                             "\nRIGHT HAND\n" + 
                                             "  IN PROGRESS:" + str(self.hands.rightHand.gestureInProgress) + 
                                             "  " + str(self.hands.rightHand.gestureCount)
                                             ) 
                self.queue.task_done() 
            except Empty:
                pass 
        
        self.displayWindow.close()
                                
if __name__ == '__main__':
  
    app = QtGui.QApplication(argv)
    root = MainApp()
    root.show()
    app.exec_()
